package com.training.controller;

import cn.dev33.satoken.util.SaResult;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.training.dto.AqiTrendStatisticDto;
import com.training.dto.OtherStatisticDto;
import com.training.dto.ProvinceStatisticDto;
import com.training.entity.Address;
import com.training.entity.ConfirmAqiData;
import com.training.entity.NativeMap;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

/**
 * @BelongsProject: environment-supervision
 * @BelongsPackage: com.training.controller
 * @Author: Tianyu Han
 * @CreateTime: 2024-05-27  09:57
 * @Description: 统计数据管理
 * @Version: 1.0
 */
@RestController
@RequestMapping("/statistics")
@Tag(name = "统计数据管理")
public class StatisticsController {

    @Operation(summary = "获取省分组统计数据")
    @GetMapping("/province")
    public SaResult getProvinceStatistics() {
        //查出NativeMap表中的所有省份
        List<NativeMap> nativeMaps = Db.lambdaQuery(NativeMap.class)
                .select(NativeMap::getProvince, NativeMap::getProvinceShort, NativeMap::getProvinceCode)
                .list().stream().distinct()
                .toList();
        //根据每个省份查出含该省份的address
        List<ProvinceStatisticDto> provinceStatisticDtos = nativeMaps.stream().map(nativeMap -> {
            List<Address> addresses = Db.lambdaQuery(Address.class).select(Address::getId)
                    .eq(Address::getProvince, nativeMap.getProvince())
                    .list();
            //查出该省份下的所有确认数据，并统计各种指标的超标数
            int sulfurExceedNum = 0;
            int carbonExceedNum = 0;
            int particulateExceedNum = 0;
            int aqiExceedNum = 0;
            for (Address address : addresses) {
                List<ConfirmAqiData> confirmAqiDatas = Db.lambdaQuery(ConfirmAqiData.class)
                        .eq(ConfirmAqiData::getAddressId, address.getId())
                        .list();
                //统计超标数
                for (ConfirmAqiData confirmAqiData : confirmAqiDatas) {
                    if (confirmAqiData.getSulfurDioxideConcentration() > 0.5) {
                        sulfurExceedNum++;
                    }
                    if (confirmAqiData.getCarbonMonoxideConcentration() > 0.5) {
                        carbonExceedNum++;
                    }
                    if (confirmAqiData.getParticulateMatter() > 100) {
                        particulateExceedNum++;
                    }
                    if (confirmAqiData.getAqi() > 2) {
                        aqiExceedNum++;
                    }
                }
            }
            //封装数据
            return ProvinceStatisticDto.builder()
                    .province(nativeMap.getProvince())
                    .provinceShort(nativeMap.getProvinceShort())
                    .code(nativeMap.getProvinceCode())
                    .sulfurExceedNum(sulfurExceedNum)
                    .carbonExceedNum(carbonExceedNum)
                    .particulateExceedNum(particulateExceedNum)
                    .aqiExceedNum(aqiExceedNum)
                    .build();
        }).toList();
        return SaResult.data(provinceStatisticDtos);
    }

    @Operation(summary = "获取aqi分布统计数据")
    @GetMapping("/aqiDistribution")
    public SaResult getAqiDistributionStatistics() {
        //统计各个等级的aqi数，aqi范围1-6
        long[] aqiNum = new long[6];
        for (int i = 1; i <= 6; i++) {
            aqiNum[i - 1] = Db.lambdaQuery(ConfirmAqiData.class)
                    .eq(ConfirmAqiData::getAqi, i)
                    .count();
        }
        return SaResult.data(aqiNum);
    }

    @Operation(summary = "获取aqi趋势统计数据")
    @GetMapping("/aqiTrend")
    public SaResult getAqiTrendStatistics() {
        //统计过去一年每个月的aqi超标数
        //先构建12个月的数据
        List<AqiTrendStatisticDto> aqiTrendStatisticDtos = new ArrayList<>();

        for (int i = 1; i < 12; i++) {
            //从一年前开始，每个月的第一天
            LocalDate startDate = LocalDate.now().minusYears(1).withMonth(i).withDayOfMonth(1);
            LocalDate endDate = startDate.plusMonths(1);
            aqiTrendStatisticDtos.add(AqiTrendStatisticDto.builder()
                    .id(i)
                    .date(startDate)
                    .aqiExceedNum(Db.lambdaQuery(ConfirmAqiData.class)
                            .between(ConfirmAqiData::getUpdateTime, startDate, endDate)
                            .gt(ConfirmAqiData::getAqi, 2)
                            .count().intValue())
                    .build());
        }
        return SaResult.data(aqiTrendStatisticDtos);
    }

    @Operation(summary = "获取其他统计数据")
    @GetMapping("/others")
    public SaResult getOthersStatistics() {
        //统计空气质量检测总数
        Long total = Db.lambdaQuery(ConfirmAqiData.class)
                .eq(ConfirmAqiData::getIsConfirmed, 1)
                .count();
        // 统计空气质量检测良好数
        Long good = Db.lambdaQuery(ConfirmAqiData.class)
                .eq(ConfirmAqiData::getIsConfirmed, 1)
                .le(ConfirmAqiData::getAqi, 2)
                .count();
        //统计省会城市覆盖率
        //nativeMap中cityCode末尾为01的是省会城市
        List<NativeMap> nativeMaps = Db.lambdaQuery(NativeMap.class)
                .select(NativeMap::getCity)
                .likeLeft(NativeMap::getCityCode, "01")
                .list();
        //从Address查出所有不重复的city
        List<Address> addresses = Db.lambdaQuery(Address.class)
                .select(Address::getCity)
                .list().stream().distinct()
                .toList();
        int cityNum = addresses.size();
        //计算address中是省会城市的数量
        int capitalCityNum = 0;
        for (Address address : addresses) {
            for (NativeMap nativeMap : nativeMaps) {
                if (address.getCity().equals(nativeMap.getCity())) {
                    capitalCityNum++;
                    break;
                }
            }
        }
        OtherStatisticDto otherStatisticDto = OtherStatisticDto.builder()
                .totalNum(total.intValue())
                .goodNum(good.intValue())
                .capitalCoverage((double) capitalCityNum / nativeMaps.size())
                .cityCoverage((double) cityNum / nativeMaps.size())
                .build();

        return SaResult.data(otherStatisticDto);
    }

}
